//
//	Builder "const.h"
//	Written by Aaron J. Miller
//
//	Used to share data between the source files.
//
#ifndef CONST_H
#define CONST_H

////////////////////////////////////////////////////////////////////////////////

#ifdef __cplusplus
extern "C" {
#endif

////////////////////////////////////////////////////////////////////////////////
// INCLUDES

// common includes
#include <errno.h>
#include <stdio.h>
#include <dirent.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#ifdef _WIN32
# include <windows.h>
#endif

// bitfield_t
#ifndef bitfield_t_defined
# define bitfield_t_defined 1
typedef size_t bitfield_t;
#endif

////////////////////////////////////////////////////////////////////////////////
// COMMON MACROS

// version
#define VERSION_MAJOR 0
#define VERSION_MINOR 2
#define VERSION (VERSION_MAJOR*100 + VERSION_MINOR)

// operating system
#define OS_MSWIN 1
#define OS_LINUX 2
#define OS_MACOS 3
#if defined(_WIN32)
# define HOST_OS OS_MSWIN
#elif defined(linux)||defined(__linux)||defined(__linux__)
# define HOST_OS OS_LINUX
#elif defined(__APPLE__)
# define HOST_OS OS_MACOS
#else
# define HOST_OS 0
#endif

// architecture
#define ARCH_X86 1
#define ARCH_AMD64 2
#define ARCH_ARM 3
#define ARCH_ARM64 4 //not here yet, reserved though
#define ARCH_PPC 5
#define ARCH_SPARC 6
#define ARCH_MIPS 7

#if defined(__amd64__)||defined(__amd64)
# define HOST_ARCH ARCH_AMD64
#elif defined(__x86_64__)||defined(__x86_64)
# define HOST_ARCH ARCH_AMD64
#elif defined(_M_X64)
# define HOST_ARCH ARCH_AMD64
#elif defined(__arm__)
# define HOST_ARCH ARCH_ARM
#elif defined(i386)||defined(__i386)||defined(__i386__)
# define HOST_ARCH ARCH_X86
#elif defined(_M_IX86)||defined(__X86__)||defined(_X86_)
# define HOST_ARCH ARCH_X86
#elif defined(__I86__)||defined(__INTEL__)
# define HOST_ARCH ARCH_X86
#elif defined(__powerpc)||defined(__powerpc__)||defined(__ppc__)
# define HOST_ARCH ARCH_PPC
#elif defined(_M_PPC)||defined(__POWERPC__)
# define HOST_ARCH ARCH_PPC
#elif defined(__sparc)||defined(__sparc)
# define HOST_ARCH ARCH_SPARC
#elif defined(__sparcv8)||defined(__sparcv9)
# define HOST_ARCH ARCH_SPARC
#elif defined(mips)||defined(__mips)||defined(__mips__)
# define HOST_ARCH ARCH_MIPS
#elif defined(_R3000)||defined(_R4000)||defined(__MIPS__)
# define HOST_ARCH ARCH_MIPS
#else
# define HOST_ARCH 0
#endif

////////////////////////////////////////////////////////////////////////////////
// COMMON FUNCTIONS

// formatting functions
const char *va(const char *format, ...);

// replacement error (fprintf(stderr,...)) functions
void i_error__(const char *file, unsigned int line, const char *func,
	const char *format, ...);
#define i_interrorf(format, ...) i_error__((const char *)0, 0, __func__,\
 format, ##__VA_ARGS__)
#define i_interror(message) i_interrorf("%s", message)
#define i_ioerrorf(file,line, format, ...) i_error__(file, line,\
 (const char *)0, format, ##__VA_ARGS__)
#define i_ioerror(file,line, message) i_ioerrorf(file, line, "%s", message)
#define i_errorf(format, ...) i_error__((const char *)0, 0, (const char *)0,\
 format, ##__VA_ARGS__)
#define i_error(message) i_errorf("%s", message)
#define i_errnoerror() i_interror(i_errnostring())

// replacement memory functions
void *i_new(size_t n);
void *i_renew(void *p, size_t n);
void i_delete(void *p);

// replacement string functions
const char *i_errnostring();
char *i_strdup(const char *src);
void i_strcpy(char *dst, size_t dstn, const char *src);
void i_strncpy(char *buf, size_t bufn, const char *src, size_t srcn);
size_t i_strcat(char *buf, size_t bufn, const char *src);
void i_inplacestrip(char *buf);

// replacement realpath() function
char *i_realpath(const char *filename, char *resolvedname, size_t maxn);

////////////////////////////////////////////////////////////////////////////////
// VARIABLE SYSTEM

// typedefs
typedef struct var_s *var_t;
typedef void(*v_assign_fn_t)(var_t, const char *);

// variable settings
#define VAR_CONST_BIT			0x00000001
#define VAR_ARRAY_BIT			0x00000002
#define VAR_SYMLINK_BIT			0x00000004

// internal variable settings
#define VAR_EXPANDEDN_BIT		0x00010000
#define VAR_EXPANDEDI_BIT		0x00020000
#define VAR_ARRAYFETCHED_BIT	0x00040000

// settings
#define VAR_MAX_INHERITENCE		256

// structures
struct var_s {
	// general information
	char *name;					//expanded name of the variable
								//NOTE: does not include parent's name
	uint32_t hash;				//hash of the name
	bitfield_t flags;			//flags (see VAR_*_BIT stuff)

	// variable usage
	union {
		var_t symlink;			//VAR_SYMLINK_BIT: pointer to the real variable
		char *text;				//else: normal variable text
								//arrays: this is a space delimited array of
								//        each element.
	} value;
	char *expanded;				//expended version

	// array information
	struct {
		char **members;			//member elements in the array

		char n_text[32];		//text version of 'n', in decimal
		char i_text[32];		//text version of 'i', in decimal

		size_t capacity;		//number of elements allocated for the array
		size_t n;				//number of elements in the array
		size_t i;				//index to the current element in the array

		var_t ptrvar;			//pointer variable to the current element
								//symlink: pointer variable to owner
								//    used to check which index to grab from
								//    during expand
	} array;

	// inheritance
	struct {
		var_t owners[VAR_MAX_INHERITENCE];

		size_t owned_index;
		var_t owned;
	} i;

	// hierarchy
	struct {
		var_t prnt;				//parent
		var_t prev,next;		//siblings
		var_t head,tail;		//children
	} h;
};

// root variable
extern var_t g_var_root;
extern var_t g_var_char[256];

// functions
void v_init();
void v_terminate();

uint32_t v_hash(const char *text);

var_t v_find(const char *name);
var_t v_findhash(var_t prnt, uint32_t hash);
var_t v_findroot(const char *name);
var_t v_findarray(var_t v);

var_t v_newhash(var_t prnt, const char *name, uint32_t hash);
var_t v_new(const char *name);
var_t v_new_const(const char *name);
var_t v_new_symlink(const char *name, var_t tovar);
var_t v_new_array(const char *name, const char *ptrname, size_t initsize);

void v_delete(var_t v);

void v_set(var_t v, const char *value);
void v_cat(var_t v, const char *value);
void v_set_array(var_t v, size_t i, const char *value);

const char *v_get(var_t v);
const char *v_get_array(var_t v, size_t i);

var_t v_var(const char *name);
void v_setvar(const char *name, const char *value);
const char *v_getvar(const char *name);

const char *v_expand(var_t v);
const char *v_finalize(var_t v);

void v_array_empty(var_t v);
void v_array_explode(var_t v, const char *value);
void v_array_push(var_t v, const char *value);

void v_array_tofirst(var_t v);
void v_array_tolast(var_t v);
void v_array_tonext(var_t v);
void v_array_toprev(var_t v);
const char *v_array_value(var_t v);
const char *v_array_expand_i(var_t v);
const char *v_array_expand_n(var_t v);

const char *v_nformat(char *buf, size_t n, const char *format);
const char *v_format(const char *format);

void v_dup(var_t dst, var_t src);
int v_foreach(var_t v, int(*fn)(var_t,size_t,void*), void *p);

////////////////////////////////////////////////////////////////////////////////

int getcpucount();

const char *getconfigdir();
void mkdirs(const char *dirs);

int isfile(const char *path);

int s_wildcard(const char *pattern, const char *source);
const char *s_getdir(char *buf, size_t n, const char *filename);
void wildcard(var_t v, const char *pattern);
void multiwildcard(var_t v, const char *path, size_t n, const char **patterns);

void s_setext(char *buf, size_t n, const char *source, const char *ext);
void seteachext(var_t v, const char *ext);

////////////////////////////////////////////////////////////////////////////////
// BUFFER SYSTEM

typedef struct buffer_s *buffer_t;

struct buffer_s {
	char filename[256];
	int line;

	char *source;
	char *p;

	buffer_t prev, next;
};
extern buffer_t g_buf_head;
extern buffer_t g_buf_tail;

void b_init();
void b_terminate();

buffer_t b_open(const char *filename);
void b_close(buffer_t b);

char b_read(buffer_t b);
char b_look(buffer_t b);

void b_error(buffer_t b, const char *format, ...);

////////////////////////////////////////////////////////////////////////////////

void setopt(const char *name, const char *value);
int isverbose();

void init(int argc, char **argv);
int main(int argc, char **argv);

int build(var_t v, size_t i, void *p);
int buildproject(var_t v, size_t i, void *p);
int buildprojectgoal(var_t v, size_t i, void *p);

int readconf(const char *filename);

int loadtoolchaindefaults();
int loadtoolchainconf(const char *step);

void readdeps(const char *filename);

////////////////////////////////////////////////////////////////////////////////

#ifdef __cplusplus
}
#endif

////////////////////////////////////////////////////////////////////////////////

#endif
